package behaviorTree

import (
	"bytes"
	. "gitee.com/kingzyt/common/objPool"
	"gitee.com/kingzyt/common/stack"

	"fmt"
	"time"
)

type NodeStackData struct {
	node      INode
	localData interface{}
	state     NodeState
}

func (self *NodeStackData) Clear() {
	self.node = nil
	self.localData = nil
	self.state = INVALID
}

var g_nodeStackDataPool = NewObjPool("g_nodeStackDataPool", 0, 0, func() interface{} {
	return &NodeStackData{}
})

type NodeStack struct {
	stack *stack.Stack
	show  bool
}

func NewNodeStack() *NodeStack {
	return &NodeStack{stack: stack.NewStack(0)}
}

func (self *NodeStack) TestShow(show bool) {
	self.show = show
}

func (self *NodeStack) PushNode(node INode, localData interface{}) {
	sd := g_nodeStackDataPool.Pull().(*NodeStackData)
	sd.node = node
	sd.localData = localData
	sd.state = BEGIN
	self.stack.Push(sd)

	if self.show {
		//fmt.Println(self.String())
		top, _, _ := self.GetTopNode()
		fmt.Println(top.GetName())
	}
}
func (self *NodeStack) PopNode() {
	sd := self.stack.Pop().(*NodeStackData)
	if sd != nil {
		sd.Clear()
		g_nodeStackDataPool.Push(sd)
	}

	/*if self.show {
		fmt.Println(self.String())
	}*/
}
func (self *NodeStack) Len() int32 {
	return self.stack.Len()
}

func (self *NodeStack) Clear() {
	for self.Len() > 0 {
		self.PopNode()
	}
}

func (self *NodeStack) GetTopNode() (node INode, state NodeState, localData interface{}) {
	obj := self.stack.PeekTop()
	if obj == nil {
		return nil, INVALID, nil
	}

	top := obj.(*NodeStackData)
	if top != nil {
		return top.node, top.state, top.localData
	}

	return nil, INVALID, nil
}

func (self *NodeStack) SetTopNodeData(state NodeState, localData interface{}) {
	obj := self.stack.PeekTop()
	if obj == nil {
		panic("no node in stack")
	}

	top := obj.(*NodeStackData)
	if top != nil {
		top.state = state
		top.localData = localData
	}
}
func (self *NodeStack) GetTopNodeData() (state NodeState, localData interface{}) {
	obj := self.stack.PeekTop()
	if obj == nil {
		panic("no node in stack")
	}

	top := obj.(*NodeStackData)
	if top != nil {
		return top.state, top.localData
	}

	return INVALID, nil
}

func (self *NodeStack) GetTopNodeState() (state NodeState) {
	obj := self.stack.PeekTop()
	if obj == nil {
		panic("no node in stack")
	}

	top := obj.(*NodeStackData)
	if top != nil {
		return top.state
	}

	return INVALID
}
func (self *NodeStack) GetTopNodeLocalData() (localData interface{}) {
	obj := self.stack.PeekTop()
	if obj == nil {
		panic("no node in stack")
	}

	top := obj.(*NodeStackData)
	if top != nil {
		return top.localData
	}

	return nil
}

func (self *NodeStack) String() string {
	info := &bytes.Buffer{}
	info.WriteString(time.Now().Format(time.RFC3339))
	info.WriteString("\n")
	self.stack.IteratorRevElems(func(v interface{}) bool {
		data := v.(*NodeStackData)
		info.WriteString(fmt.Sprintf("%s[%s], %s, %v\n", data.node.GetType(), data.node.GetName(), data.state, data.localData))
		return true
	})
	info.WriteString("-----------------------")
	return info.String()
}
